package cn.tth.test.game.bean;

import cn.tth.test.game.annotations.Bean;
import cn.tth.test.game.annotations.DI;
import lombok.extern.slf4j.Slf4j;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Slf4j
public class BeanUtil extends BeanApplicationContext{

    public static Map<String,BeanDefinition> createBean(List<String> classNameList) throws ClassNotFoundException {
        List<Class<?>> beanClass = new ArrayList<>();
        for (String className : classNameList) {
            Class<?> aClass = Class.forName(className);
            if(isBean(aClass)){
                beanClass.add(aClass);
            }
        }
        for (Class<?> aClass : beanClass) {
            //创建bean
            createBean(aClass);
        }
        return beanContext;
    }


    public static String createBean(Class<?> aClass) {
            String beanName = "";
            try {
                //实例化bean
                beanName = toBean(aClass);
                //依赖注入
                dependencyInjection(beanName);
                return beanName;
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
                log.warn("create error:",e);
            }
            return beanName;
    }

    private static void dependencyInjection(String beanName) throws IllegalAccessException {
        BeanDefinition beanDefinition = beanContext.get(beanName);
        Class<?> beanClass = beanDefinition.getBeanClass();

        //获取需要注入的字段
        List<Field> fieldList = getDIField(beanClass);

        for (Field field : fieldList) {
            String fieldName = field.getName();
            BeanDefinition fieldBean = beanContext.get(fieldName);
            if (Objects.isNull(fieldBean)) {
                //如果容器不存在
                Class<?> fieldDeclaringClass = field.getType();
                String createBeanName = createBean(fieldDeclaringClass);
                fieldBean = beanContext.get(createBeanName);
            }
            field.setAccessible(true);
            field.set(beanDefinition.getBean(), fieldBean.getBean());
        }

    }

    private static List<Field> getDIField(Class<?> beanClass) {

        Field[] fields = beanClass.getDeclaredFields();

        List<Field> fieldList = new ArrayList<>();
        for (Field field : fields) {
            Annotation[] declaredAnnotations = field.getDeclaredAnnotations();
            for (Annotation annotation : declaredAnnotations) {
                if (annotation instanceof DI) {
                    fieldList.add(field);
                }
            }
        }
        return fieldList;
    }

    private static String toBean(Class<?> aClass) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        String beanName = aClass.getSimpleName();
        beanName = beanName.substring(0, 1).toLowerCase() + beanName.substring(1);
        BeanDefinition beanDefinition = new BeanDefinition(aClass, beanName);
        beanContext.put(beanName,beanDefinition);
        beanClassContext.put(aClass,beanDefinition);
        return beanName;
    }

    /**
     * 是否是一个bean
     *
     * @param aClass 一个类
     * @return boolean
     */
    private static boolean isBean(Class<?> aClass) {
        Annotation[] declaredAnnotations = aClass.getDeclaredAnnotations();
        for (Annotation annotation : declaredAnnotations) {
            if(annotation instanceof Bean){
                return true;
            }
        }
        return false;
    }
}
